using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace gngui
{
    public partial class MainForm : Form
    {
        private byte[] m_renderBmp = null;
        private System.Threading.Timer m_timer = null;
        private System.Threading.Timer m_DemoTimer = null;
        private int m_hMapData = 0;
        private bool m_bDemoStart = false;
        private ObjectInfo[] m_ObjectInfos = null;

        private float m_fMapCenterX = 0.0f;
        private float m_fMapCenterY = 0.0f;
        private float m_fScale = 1.0f;

        private const int DB_RANGE_X = 10000;
        private const int DB_RANGE_Y = 10000;

        public MainForm()
        {
            InitializeComponent();

            btnDemo.Enabled = false;
            btnZoomIn.Enabled = false;
            btnZoomOut.Enabled = false;
            btnScrollDown.Enabled = false;
            btnScrollUp.Enabled = false;
            btnScrollLeft.Enabled = false;
            btnScrollRight.Enabled = false;

            m_renderBmp = new byte[panelMap.Width * panelMap.Height * 4];

            ServiceWrapper.Initialize(this.Handle, this.panelMap.Width, this.panelMap.Height);

        }

        private void radioButton4_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            textBoxRadius.Text = (trackBarRadius.Value * (2.5 - 0.5) / trackBarRadius.Maximum + 0.5).ToString();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            textBoxRadius.Text = (trackBarRadius.Value * (2.5 - 0.5) / trackBarRadius.Maximum + 0.5).ToString();
            textBoxObject.Text = (trackBarObject.Value * (500 - 100) / trackBarObject.Maximum + 100).ToString();
            textBoxT.Text = (trackBarT.Value * (30 - 5) / trackBarT.Maximum + 5).ToString();
            textBoxL.Text = (trackBarL.Value * (30 - 5) / trackBarL.Maximum + 5).ToString();
            textBoxAmbig.Text = (trackBarAmbig.Value * (0.5 - 0.1) / trackBarAmbig.Maximum + 0.1).ToString();
            textBoxThiter.Text = (trackBarThiter.Value * (0.9 - 0.3) / trackBarThiter.Maximum + 0.3).ToString();
            textBoxSpeed.Text = (trackBarSpeed.Value * (90 - 30) / trackBarSpeed.Maximum + 30).ToString();

        }

        private void trackBar5_Scroll(object sender, EventArgs e)
        {
            textBoxAmbig.Text = (trackBarAmbig.Value * (0.5 - 0.0) / trackBarAmbig.Maximum + 0.0).ToString();
        }

        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            textBoxObject.Text = (trackBarObject.Value * (500 - 100) / trackBarObject.Maximum + 100).ToString();
        }

        private void trackBar3_Scroll(object sender, EventArgs e)
        {
            textBoxT.Text = (trackBarT.Value * (30 - 5) / trackBarT.Maximum + 5).ToString();
        }

        private void trackBar4_Scroll(object sender, EventArgs e)
        {
            textBoxL.Text = (trackBarL.Value * (30 - 5) / trackBarL.Maximum + 5).ToString();
        }

        private void trackBar6_Scroll(object sender, EventArgs e)
        {
            textBoxThiter.Text = (trackBarThiter.Value * (0.9 - 0.3) / trackBarThiter.Maximum + 0.3).ToString();
        }

        private void trackBar7_Scroll(object sender, EventArgs e)
        {
            textBoxSpeed.Text = (trackBarSpeed.Value * (90 - 30) / trackBarSpeed.Maximum + 30).ToString();
        }

        private void btnGenerate_Click(object sender, EventArgs e)
        {
            string strDataPath = Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf('\\'));

            if(radioBtnOL.Checked)
            {
                strDataPath += "\\OL\\";
            }
            else if(radioBtnTG.Checked)
            {
                strDataPath += "\\TG\\";
            }

            DObjectType dObjType = new DObjectType();
            if(radioBtnUniform.Checked)
            {
                dObjType = DObjectType.DObjectType_Uniform;
            }
            else if(radioBtnZipf.Checked)
            {
                dObjType = DObjectType.DObjectType_Zipf;
            }

            if (m_hMapData != 0)
                ServiceWrapper.UnloadData(m_hMapData);

            int iObjectCnt = int.Parse(this.textBoxObject.Text);
            ServiceWrapper.GenerateData(strDataPath, dObjType, iObjectCnt);

            ServiceWrapper.LoadData(strDataPath, ref m_hMapData);

            ServiceWrapper.GetObjectCnt(ref iObjectCnt);

            m_ObjectInfos = new ObjectInfo[iObjectCnt];

            ServiceWrapper.GetObjectPosition(ref m_ObjectInfos[0]);

            panelMap.Invalidate();

            this.btnScrollLeft.Enabled = true;
            this.btnScrollRight.Enabled = true;
            this.btnScrollUp.Enabled = true;
            this.btnScrollDown.Enabled = true;
            this.btnZoomIn.Enabled = true;
            this.btnZoomOut.Enabled = true;
            this.btnDemo.Enabled = true;
        }

        private void ConvertGeoToGrpah(ref Point stGeo,ref Point stGraph)
        {
            float fScaleX = (float)panelMap.Width / DB_RANGE_X * m_fScale;
            float fScaleY = (float)panelMap.Height / DB_RANGE_Y * m_fScale;


            stGraph.X = (int)((stGeo.X - m_fMapCenterX) * fScaleX);
            stGraph.Y = (int)((stGeo.Y - m_fMapCenterY) * fScaleY);

            stGraph.X += panelMap.Width / 2;
            stGraph.Y += panelMap.Height / 2; 
        }

        private void drawSplitNode(Graphics gl)
        {
            int iSplitNodeCnt = 0;

            ServiceWrapper.GetSplitNodeCnt(ref iSplitNodeCnt);

            if(iSplitNodeCnt > 0)
            {
                SplitNodeInfo[] astSplitNode = new SplitNodeInfo[iSplitNodeCnt];

                ServiceWrapper.GetSplitNodeInfo(ref astSplitNode[0]);

                for (int i = 0; i < astSplitNode.Length; i++)
                {
                    // Create point for upper-left corner of drawing.
                    Point stGraph = new Point();
                    Point stGeo = new Point(astSplitNode[i].iPosX, astSplitNode[i].iPosY);

                    ConvertGeoToGrpah(ref stGeo, ref stGraph);

                    Pen redPen = new Pen(Brushes.Red);
                    gl.DrawEllipse(redPen, stGraph.X - 2, stGraph.Y - 2, 4, 4);

                }
            }
        }

        private void drawSearchObject(Graphics gl)
        {
            int iSearchObjCnt = 0;
            ServiceWrapper.GetSearchObjCnt(ref iSearchObjCnt);

            if(iSearchObjCnt > 0)
            {
                ObjectInfo[] astObjectInfo = new ObjectInfo[iSearchObjCnt];

                ServiceWrapper.GetSearchObjInfo(ref astObjectInfo[0]);

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < astObjectInfo.Length; i++)
                {
                    sb.AppendFormat("O_{0},", astObjectInfo[i].iObjID);
                }

                this.txtResult.Text = sb.ToString();
            }
            else
            {
                this.txtResult.Text = "No Result !";
            }
        }

        private void drawObjectString(Graphics gl)
        {
            if (m_ObjectInfos != null)
            {
                for (int i = 0; i < m_ObjectInfos.Length; i++)
                {
                    // Create string to draw.
                    String drawString = String.Format("O_{0}", m_ObjectInfos[i].iObjID);

                    // Create font and brush.
                    Font drawFont = new Font("Arial", 8);
                    SolidBrush drawBrush = new SolidBrush(Color.Black);

                    // Create point for upper-left corner of drawing.
                    Point stGraph = new Point();
                    Point stGeo = new Point(m_ObjectInfos[i].iPosX, m_ObjectInfos[i].iPosY);

                    ConvertGeoToGrpah(ref stGeo, ref stGraph);

                    // Draw string to screen.
                    gl.DrawString(drawString, drawFont, drawBrush, stGraph);
                }
            }
        }

        private void panelMap_Paint(object sender, PaintEventArgs e)
        {
            Graphics gl = e.Graphics;

            ServiceWrapper.GetMapCenterPoint(ref m_fMapCenterX, ref m_fMapCenterY);
            ServiceWrapper.GetMapScale(ref m_fScale);

            Bitmap bmp = new Bitmap(panelMap.Width, panelMap.Height, PixelFormat.Format32bppArgb);
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);

            // Get the address of the first line.
            IntPtr ptr = bmpData.Scan0;

            // Declare an array to hold the bytes of the bitmap.
            // This code is specific to a bitmap with 24 bits per pixels.
            int bytes = bmp.Width * bmp.Height * 4;

            ServiceWrapper.DoRender(ref m_renderBmp[0]);

            // Copy the RGB values back to the bitmap
            System.Runtime.InteropServices.Marshal.Copy(m_renderBmp, 0, ptr, bytes);

            // Unlock the bits.
            bmp.UnlockBits(bmpData);

            gl.DrawImage(bmp, 0, 0);

            this.drawObjectString(gl);
            this.drawSplitNode(gl);
            this.drawSearchObject(gl);
           
        }

        private void callback_ZoomIn(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_ZOOM_IN);
            panelMap.Invalidate();
        }

        private void callback_ZoomOut(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_ZOOM_OUT);
            panelMap.Invalidate();
        }

        private void callback_ScrollUp(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_SCROLL_UP);
            panelMap.Invalidate();
        }

        private void callback_ScrollDown(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_SCROLL_DOWN);
            panelMap.Invalidate();
        }

        private void callback_ScrollLeft(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_SCROLL_LEFT);
            panelMap.Invalidate();
        }

        private void callback_ScrollRight(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_SCROLL_RIGHT);
            panelMap.Invalidate();
        }

        private void callback_DemoMove(object state)
        {
            ServiceWrapper.ExecuteCommand(CommandType.COMMAND_DEMO_MOVE);
            panelMap.Invalidate();
        }

        private void btnZoomIn_MouseDown(object sender, MouseEventArgs e)
        {
            TimerCallback timerDelegate = new TimerCallback(callback_ZoomIn);
            m_timer = new System.Threading.Timer(timerDelegate, null, 0, 200);
        }

        private void btnZoomIn_MouseUp(object sender, MouseEventArgs e)
        {
            m_timer.Dispose();
            m_timer = null;
        }

        private void btnZoomOut_MouseDown(object sender, MouseEventArgs e)
        {
            TimerCallback timerDelegate = new TimerCallback(callback_ZoomOut);
            m_timer = new System.Threading.Timer(timerDelegate, null, 0, 200);
        }

        private void btnZoomOut_MouseUp(object sender, MouseEventArgs e)
        {
            m_timer.Dispose();
            m_timer = null;
        }

        private void btnDemo_Click(object sender, EventArgs e)
        {
            if(m_bDemoStart == false)
            {
                btnScrollDown.Enabled = false;
                btnScrollUp.Enabled = false;
                btnScrollLeft.Enabled = false;
                btnScrollRight.Enabled = false;
                btnGenerate.Enabled = false;

                SearchType searchType = new SearchType();
                if(radioBtnNDMR.Checked)
                {
                    searchType = SearchType.SearchType_NDMR;
                }
                else if(radioBtnEDMR.Checked)
                {
                    searchType = SearchType.SearchType_EDMR;
                }

                ServiceWrapper.CalcRouteInfo(
                    m_hMapData, 
                    searchType,
                    float.Parse(textBoxRadius.Text)*1000,
                    int.Parse(textBoxL.Text)*1000, 
                    float.Parse(textBoxThiter.Text), 
                    int.Parse(textBoxSpeed.Text),
                    float.Parse(this.textBoxAmbig.Text));

                ServiceWrapper.ExecuteCommand(CommandType.COMMAND_DEMO_START);

                TimerCallback timerDelegate = new TimerCallback(callback_DemoMove);
                m_DemoTimer = new System.Threading.Timer(timerDelegate, null, 0, int.Parse(this.textBoxT.Text)*6);

                this.btnDemo.Text = "stop";
                m_bDemoStart = true;

            }
            else
            {   

                btnScrollDown.Enabled = true;
                btnScrollUp.Enabled = true;
                btnScrollLeft.Enabled = true;
                btnScrollRight.Enabled = true;
                btnGenerate.Enabled = true;

                ServiceWrapper.ReleaseRouteInfo(m_hMapData);
                panelMap.Invalidate();

                ServiceWrapper.ExecuteCommand(CommandType.COMMAND_DEMO_END);

                m_DemoTimer.Dispose();
                m_DemoTimer = null;

                this.btnDemo.Text = "start";
                m_bDemoStart = false;

            }
            

            
        }

        private void btnScrollUp_MouseDown(object sender, MouseEventArgs e)
        {
            TimerCallback timerDelegate = new TimerCallback(callback_ScrollUp);
            m_timer = new System.Threading.Timer(timerDelegate, null, 0, 200);
        }

        private void btnScrollUp_MouseUp(object sender, MouseEventArgs e)
        {
            m_timer.Dispose();
            m_timer = null;
        }

        private void btnScrollLeft_MouseDown(object sender, MouseEventArgs e)
        {
            TimerCallback timerDelegate = new TimerCallback(callback_ScrollLeft);
            m_timer = new System.Threading.Timer(timerDelegate, null, 0, 200);
        }

        private void btnScrollLeft_MouseUp(object sender, MouseEventArgs e)
        {
            m_timer.Dispose();
            m_timer = null;
        }

        private void btnScrollRight_MouseDown(object sender, MouseEventArgs e)
        {
            TimerCallback timerDelegate = new TimerCallback(callback_ScrollRight);
            m_timer = new System.Threading.Timer(timerDelegate, null, 0, 200);
        }

        private void btnScrollRight_MouseUp(object sender, MouseEventArgs e)
        {
            m_timer.Dispose();
            m_timer = null;
        }

        private void btnScrollDown_MouseDown(object sender, MouseEventArgs e)
        {
            TimerCallback timerDelegate = new TimerCallback(callback_ScrollDown);
            m_timer = new System.Threading.Timer(timerDelegate, null, 0, 200);
        }

        private void btnScrollDown_MouseUp(object sender, MouseEventArgs e)
        {
            m_timer.Dispose();
            m_timer = null;
        }

        
    }
}